package com.example.demo.aop;

import com.example.demo.common.response.ResponseData;
import com.example.demo.util.gson.GsonUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
@Slf4j
public class ControllerLogAspect {
	/**
	 * ..表示包及子包 该方法代表controller层的所有方法
	 */
	@Pointcut("execution(public * com.example.demo..controller.*Controller.*(..)))")
	public void controllerMethod() {
	}
	
	
	/**
	 * 方法执行前
	 *
	 * @param joinPoint
	 */
	@Before("controllerMethod()")
	public void LogRequestInfo(JoinPoint joinPoint) {
		try {
			String requestUuid = ContextDadaHolder.getRequestUuid();
			ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
			HttpServletRequest request = attributes.getRequest();
			StringBuilder requestLog = new StringBuilder();
			Signature signature = joinPoint.getSignature();
			Map<String, String> heads = new HashMap<>();
			Enumeration<String> enumeration = request.getHeaderNames();
			while (enumeration.hasMoreElements()) {
				String name = enumeration.nextElement();
				String values = request.getHeader(name);
				heads.put(name, values);
			}
			String value = ((MethodSignature) signature).getMethod().getAnnotation(ApiOperation.class).value();
			if(StringUtils.isNotBlank(value) && !"null".equals(value)) {
				requestLog.append(value).append("\n");
			}
			requestLog.append("请求UUID：").append(requestUuid).append("\n")
					.append("请求信息：").append("URL = {").append(request.getRequestURI()).append("},\n")
					.append("请求头 = ").append(GsonUtil.GsonString(heads)).append(",\n")
					.append("请求方式 = {").append(request.getMethod()).append("},\n")
					.append("请求IP = {").append(request.getRemoteAddr()).append("},\n")
					.append("类方法 = {").append(signature.getDeclaringTypeName()).append(".")
					.append(signature.getName()).append("},\n");
			
			// 处理请求参数
			String[] paramNames = ((MethodSignature) signature).getParameterNames();
			Object[] paramValues = joinPoint.getArgs();
			int paramLength = null == paramNames ? 0 : paramNames.length;
			if (paramLength == 0) {
				requestLog.append("请求参数 = {} ");
			} else {
				requestLog.append("请求参数 = [");
				for (int i = 0; i < paramLength; i++) {
					
					String key = paramNames[i];
					String val;
					if (paramValues[i] instanceof HttpServletResponse) {
						val = "HttpServletResponse";
					} else {
						val = GsonUtil.GsonString(paramValues[i]);
					}
					requestLog.append(key)
							.append("=")
							.append(val);
					if (i < paramLength - 1) {
						requestLog.append(",");
					} else {
						requestLog.append("]");
					}
				}
			}
			log.info("\n\n<---------请求信息 start--------->\n请求内容:{}\n<---------请求信息 end--------->\n\n",
					requestLog.toString());
		} catch (Exception e) {
			log.error("请求日志打印异常:{}", e.getMessage());
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 方法执行后
	 *
	 * @param obj
	 */
	@AfterReturning(returning = "obj", pointcut = "controllerMethod()")
	public void logResultVOInfo(Object obj) {
		try {
			String requestUuid = ContextDadaHolder.getRequestUuid();
			String requestUrl = ContextDadaHolder.getRequestUrl();
			
			if (obj instanceof ResponseData) {
				ResponseData resultVO = (ResponseData) obj;
				log.info("\n\n<---------响应结果 start--------->\n请求UUID:{}\n请求地址:{}\n响应状态:{}\n响应信息:{}\n响应结果:{}\n<---------响应结果 end--------->\n\n",
						requestUuid, requestUrl, resultVO.getStatus(), resultVO.getMessage(), resultVO.getData());
			}
		} catch (Exception e) {
			log.error("响应日志打印异常:{}", e.getMessage());
			e.printStackTrace();
		}
	}
}
